package com.wg.core.properties;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 全局配置管理中心
 *
 * <h2>核心职责</h2>
 * <ul>
 * <li><b>统一入口</b>：提供全局静态方法访问配置</li>
 * <li><b>自动扫描</b>：动态加载扩展配置源</li>
 * <li><b>对象缓存</b>：减少重复转换开销</li>
 * <li><b>生命周期管理</b>：初始化配置系统</li>
 * </ul>
 *
 * <h3>架构设计</h3>
 *
 * <pre>
 *   +-------------------------+
 *   |       PropertiesMgr     |
 *   | (全局配置访问入口)        |
 *   +------------+------------+
 *                |
 *   +------------v------------+  +----------------------+
 *   |       IProperties       |  | PropertiesLoader     |
 *   | (配置访问接口代理)        |  | (配置加载引擎)        |
 *   +-------------------------+  +----------------------+
 *                |                           |
 *   +------------v------------+  +-----------v----------+
 *   |   DefaultProperties     |  | IPropertiesLoader    |
 *   | (基础实现)               |  | (扩展配置源接口)       |
 *   +-------------------------+  +----------------------+
 * </pre>
 *
 * <h3>典型使用场景</h3>
 *
 * <pre>
 * <code>
 * // 初始化配置系统（应用启动时调用）
 * PropertiesMgr.load("com.example.config", args);
 *
 * // 获取简单配置
 * String appName = PropertiesMgr.getStr("app.name");
 *
 * // 获取复杂对象
 * DatabaseConfig dbConfig = PropertiesMgr.toBean(DatabaseConfig.class, "db");
 *
 * // 获取列表配置
 * List<Server> servers = PropertiesMgr.toList(Server.class, "servers");
 * </code>
 * </pre>
 *
 * @author 少爷123
 */
public class PropertiesMgr {
    private static final Log log = LogFactory.get();

    /**
     * 对象缓存：存储已转换的配置对象（类名->实例）
     */
    private static final Map<String, Object> BEAN_CACHE = new ConcurrentHashMap<>(32);

    /**
     * 全局配置访问接口实例
     */
    private static volatile IProperties properties;

    /**
     * 新增加载状态标识
     */
    private static boolean isLoaded = false;

    /**
     * 初始化配置系统
     *
     * <p>
     * <b>执行流程：</b>
     * <ol>
     * <li>加载基础配置（命令行+配置文件）</li>
     * <li>扫描扩展配置加载器</li>
     * <li>合并所有配置源</li>
     * <li>初始化全局访问接口</li>
     * </ol>
     *
     * @param pack 扫描包路径（用于查找IPropertiesLoader实现）
     * @param args 命令行参数
     */
    public static synchronized void load(String pack, String... args) {
        if (isLoaded) {
            log.warn("Configuration system already initialized");
            return;
        }

        try {
            PropertiesLoader loader = new PropertiesLoader();
            Map<String, String> map = loader.loadProperties(args);
            propertyScan(pack, map);
            properties = new DefaultProperties(map);
            isLoaded = true;
            log.info("Configuration system initialized successfully");
        } catch (Exception e) {
            log.error("Failed to initialize configuration system", e);
            // 创建空配置防止后续NPE
            properties = new DefaultProperties(Collections.emptyMap());
        }
    }

    private static void checkInitialized() {
        if (!isLoaded) {
            throw new IllegalStateException("PropertiesMgr not initialized. Call load() first.");
        }
    }

    /**
     * 获取字符串配置（无默认值）
     *
     * @see IProperties#getStr(String)
     */
    public static String getStr(String key) {
        return getStr(key, null);
    }

    /**
     * 获取字符串配置（带默认值）
     *
     * @see IProperties#getStr(String, String)
     */
    public static String getStr(String key, String defaultValue) {
        checkInitialized();
        return properties.getStr(key, defaultValue);
    }

    /**
     * 获取整型配置（带默认值）
     *
     * @see IProperties#getInt(String, Integer)
     */
    public static Integer getInt(String key, Integer defaultValue) {
        checkInitialized();
        return properties.getInt(key, defaultValue);
    }

    /**
     * 获取长整型配置（带默认值）
     *
     * @see IProperties#getLong(String, Long)
     */
    public static Long getLong(String key, Long defaultValue) {
        checkInitialized();
        return properties.getLong(key, defaultValue);
    }

    /**
     * 获取布尔值配置（带默认值）
     *
     * @see IProperties#getBool(String, Boolean)
     */
    public static Boolean getBool(String key, Boolean defaultValue) {
        checkInitialized();
        return properties.getBool(key, defaultValue);
    }

    /**
     * 获取浮点数配置（带默认值）
     *
     * @see IProperties#getFloat(String, Float)
     */
    public static Float getFloat(String key, Float defaultValue) {
        checkInitialized();
        return properties.getFloat(key, defaultValue);
    }

    /**
     * 获取浮点数配置（带默认值）
     *
     * @see IProperties#getDouble(String, Double)
     */
    public static Double getDouble(String key, Double defaultValue) {
        checkInitialized();
        return properties.getDouble(key, defaultValue);
    }

    /**
     * 获取短整型配置（带默认值）
     *
     * @see IProperties#getShort(String, Short)
     */
    public static Short getShort(String key, Short defaultValue) {
        checkInitialized();
        return properties.getShort(key, defaultValue);
    }

    /**
     * 获取byte配置（带默认值）
     *
     * @see IProperties#getByte(String, Byte)
     */
    public static Byte getByte(String key, Byte defaultValue) {
        checkInitialized();
        return properties.getByte(key, defaultValue);
    }

    /**
     * 获取日期配置（带默认值）
     *
     * @see IProperties#getDate(String, Date)
     */
    public static Date getDate(String key, Date defaultValue) {
        checkInitialized();
        return properties.getDate(key, defaultValue);
    }

    /**
     * 获取枚举配置（带默认值）
     *
     * @see IProperties#getEnum(Class, String, E)
     */
    public static <E extends Enum<E>> E getEnum(Class<E> clazz, String key, E defaultValue) {
        checkInitialized();
        return properties.getEnum(clazz, key, defaultValue);
    }

    /**
     * 获取枚举配置（带默认值）
     *
     * @see IProperties#getEnum(Class, String)
     */
    public static <E extends Enum<E>> E getEnum(Class<E> clazz, String key) {
        checkInitialized();
        return properties.getEnum(clazz, key);
    }

    /**
     * 转换配置为JavaBean（带缓存）
     *
     * <p>
     * <b>缓存机制：</b>
     * 每个类只转换一次，后续调用直接返回缓存对象
     * </p>
     * 缓存键：类名 + "|" + 前缀，避免不同前缀的同类型对象冲突
     * </p>
     *
     * @param <T>       Bean类型
     * @param beanClass 目标类
     * @param prefix    配置前缀
     * @return 配置对象实例
     *
     * <p>
     * <b>注意事项：</b>
     * 1. 配置变更后需重启应用生效<br>
     * 2. 适用于不变配置（如数据库连接信息）
     * </p>
     */
    @SuppressWarnings("unchecked")
    public static <T> T toBean(Class<T> beanClass, String prefix) {
        checkInitialized();

        String cacheKey = beanClass.getName() + "|" + prefix;
        return (T) BEAN_CACHE.computeIfAbsent(cacheKey, k -> {
            T instance = properties.toBean(beanClass, prefix);
            if (instance == null) {
                log.warn("Failed to create bean instance for {} with prefix {}", beanClass, prefix);
                // 创建空实例防止重复计算
                return Optional.empty();
            }
            return instance;
        });
    }

    /**
     * 转换配置为对象列表（带缓存）
     *
     * @see #toBean(Class, String) 缓存机制相同
     */
    @SuppressWarnings("unchecked")
    public static <T> List<T> toList(Class<T> beanClass, String prefix) {
        checkInitialized();

        String cacheKey = beanClass.getName() + "|" + prefix;
        return (List<T>) BEAN_CACHE.computeIfAbsent(cacheKey, k -> {
            List<T> list = properties.toList(beanClass, prefix);
            return list != null ? list : Collections.emptyList();
        });
    }

    /**
     * 转换配置为Map结构（带缓存）
     *
     * @see #toBean(Class, String) 缓存机制相同
     */
    @SuppressWarnings("unchecked")
    public static <T> Map<String, T> toMap(Class<T> beanClass, String prefix) {
        checkInitialized();

        String cacheKey = beanClass.getName() + "|" + prefix;
        return (Map<String, T>) BEAN_CACHE.computeIfAbsent(cacheKey, k -> {
            Map<String, T> map = properties.toMap(beanClass, prefix);
            return map != null ? map : Collections.emptyMap();
        });
    }

    /**
     * 清除所有缓存对象
     *
     * <p>
     * 适用于配置热更新场景
     * </p>
     */
    public static void clearCache() {
        BEAN_CACHE.clear();
        log.info("Configuration cache cleared");
    }

    /**
     * 清除指定类型的缓存对象
     */
    public static void clearCache(Class<?> beanClass) {
        BEAN_CACHE.keySet().removeIf(key -> key.startsWith(beanClass.getName() + "|"));
        log.info("Cache cleared for {}", beanClass.getName());
    }

    /**
     * 获取所有配置键
     *
     * @see IProperties#getPropertyNames()
     */
    public static Set<String> getPropertyNames() {
        return properties.getPropertyNames();
    }

    /**
     * 扫描并加载扩展配置（增强错误处理）
     *
     * <p>
     * 在指定包路径下查找所有实现IPropertiesLoader的类，
     * 实例化并调用其load()方法加载额外配置
     * </p>
     *
     * @param pack 扫描包路径
     * @param map  目标配置Map（扩展配置将合并到此Map）
     */
    private static void propertyScan(String pack, Map<String, String> map) {
        if (StrUtil.isBlank(pack)) {
            log.warn("No package specified for property scan");
            return;
        }

        Set<Class<?>> classesSet = ClassUtil.scanPackageBySuper(pack, IPropertiesLoader.class);
        if (classesSet.isEmpty()) {
            log.debug("No IPropertiesLoader implementations found in package: {}", pack);
            return;
        }

        for (Class<?> clazz : classesSet) {
            try {
                IPropertiesLoader loader = (IPropertiesLoader) ReflectUtil.newInstance(clazz);
                loader.load(map);
                log.info("Loaded configuration from: {}", clazz.getName());
            } catch (Exception e) {
                log.error("Failed to load configuration from {}", clazz.getName(), e);
            }
        }
    }
}